package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.bean.BeanUtil;
import com.atguigu.tingshu.common.cache.CacheOperationType;
import com.atguigu.tingshu.common.cache.GuiGuCache;
import com.atguigu.tingshu.common.cache.GuiGuCached;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.UserPaidAlbum;
import com.atguigu.tingshu.model.user.UserPaidTrack;
import com.atguigu.tingshu.user.mapper.UserInfoMapper;
import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper;
import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;

    @Autowired
    private UserPaidTrackMapper userPaidTrackMapper;

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    @SneakyThrows
    @Override
    public Map<String, String> wxLogin(String code) {
        // 外部服务调用异常，应该捕获
        WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
        if (sessionInfo != null) {
            // 用户唯一标识 OpenID
            String openid = sessionInfo.getOpenid();
            // 从数据库中查询是否为新用户
            LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserInfo::getWxOpenId, openid);
            UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
            if (userInfo == null) {
                // 创建新用户
                userInfo = new UserInfo();
                userInfo.setWxOpenId(openid);
                userInfo.setAvatarUrl("https://img0.baidu.com/it/u=1801626109,2371545181&fm=253&fmt=auto&app=138&f=JPEG?w=261&h=261");
                userInfo.setNickname("初始用户:" + openid);
                userInfo.setIsVip(0);
                userInfoMapper.insert(userInfo);
                rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT, userInfo.getId().toString());
            }
            // 创建token，存入redis，但是要将用户信息隐藏，因为后续需要从redis中取得用户信息回显数据
            String token = UUID.randomUUID().toString().replaceAll("-", "");
            UserInfoVo userInfoVo = BeanUtil.copyProperties(userInfo, UserInfoVo.class);
            redisTemplate.opsForValue().set(RedisConstant.USER_LOGIN_KEY_PREFIX + token, userInfoVo, RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);
            HashMap<String, String> tokenMap = new HashMap<>();
            tokenMap.put("token", token);
            return tokenMap;
        }

        return null;
    }

    @Override
    //@GuiGuCache(prefix = "userInfo:")
    @GuiGuCached(prefix = "album:userinfo:")
    public UserInfoVo getUserInfoById(Long userId) {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        UserInfoVo userInfoVo = BeanUtil.copyProperties(userInfo, UserInfoVo.class);
        return userInfoVo;
    }

    /**
     * 此时需要删除redis中的数据,延迟双删
     * @param userId
     * @param userInfoVo
     */
    @Override
    public void updateUser(Long userId, UserInfoVo userInfoVo) {
        try {
            // 1.获取请求中的token
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            String token = null;

            if (requestAttributes != null) {
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
                HttpServletRequest request = servletRequestAttributes.getRequest();
                token = request.getHeader("token");

                // 2.先删除redis中的数据
                if (token != null && !token.isEmpty()) {
                    redisTemplate.delete(RedisConstant.USER_LOGIN_KEY_PREFIX + token);
                }
            }

            // 3.更新数据库中的数据
            UserInfo userInfo = new UserInfo();
            userInfo.setId(userId);
            userInfo.setNickname(userInfoVo.getNickname());
            userInfo.setAvatarUrl(userInfoVo.getAvatarUrl());
            userInfoMapper.updateById(userInfo);

            // 4.异步延迟删除redis中的数据
            if (token != null && !token.isEmpty()) {
                String finalToken = token; // 为了在lambda表达式中使用
                CompletableFuture.runAsync(() -> {
                    try {
                        TimeUnit.SECONDS.sleep(RedisConstant.USER_LOGIN_KEY_TIMEOUT);
                        redisTemplate.delete(RedisConstant.USER_LOGIN_KEY_PREFIX + finalToken);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                });
            }
        } catch (Exception e) {
            log.error("更新用户信息失败: userId={}, error={}", userId, e.getMessage());
            throw new RuntimeException("更新用户信息失败", e);
        }
    }

    @Override
    public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> checkedTrackIds) {
        Map<Long, Integer> checkedTrackIdsMap = new HashMap<>();
        // 先判断用户是否购买了整张专辑
        LambdaQueryWrapper<UserPaidAlbum> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserPaidAlbum::getUserId, userId);
        queryWrapper.eq(UserPaidAlbum::getAlbumId, albumId);
        UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(queryWrapper);
        if(userPaidAlbum != null){
            // 表示用户已经购买了整张专辑,专辑内的音频均为免费
            for (Long checkedTrackId : checkedTrackIds) {
                checkedTrackIdsMap.put(checkedTrackId, 1);
            }
            return checkedTrackIdsMap;
        }else {
            // 用户没有购买整张专辑，则判断用户是否购买了专辑内的声音
            LambdaQueryWrapper<UserPaidTrack> userPaidTrackQueryWrapper = new LambdaQueryWrapper<>();
            userPaidTrackQueryWrapper.eq(UserPaidTrack::getUserId, userId);
            userPaidTrackQueryWrapper.in(UserPaidTrack::getTrackId, checkedTrackIds);
            // 查询出已经购买的专辑内的音频列表
            List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(userPaidTrackQueryWrapper);
            for (Long checkedTrackId : checkedTrackIds) {
                checkedTrackIdsMap.put(checkedTrackId,
                        userPaidTrackList.stream().anyMatch(userPaidTrack -> userPaidTrack.getTrackId().equals(checkedTrackId)) ? 1 : 0);
            }
            return checkedTrackIdsMap;
        }

    }

}
